﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
//using System.Threading.Tasks;
using System.Web;

namespace HyperlinkTagEditor.App
{
    public class RegexResult
    {
        public int Index { get; set; }
        public String Value { get; set; }

        public override string ToString()
        {
            return Index.ToString() + " | " + Value;
        }


    }
    public static class URLUtilities
    {

        //const String URL_REG_EXP = @"(https?|ftp|file)\://[A-Za-z0-9\.\-]+(/[A-Za-z0-9\?\&\=;\+!'\(\)\*\-\._~${}%]*)*";
        //private static Logger logger = LogManager.GetCurrentClassLogger();
        //const String URL_REG_EXP = @"(https?|ftp|file)\://[A-Za-z0-9\.\-?_=&{}$\p{S}\p{C}\\%!\(\)]+(/[A-Za-z0-9\?\&\=;\+!'\(\)\*\-\._~${}%\p{S}\p{C}\\\(\)]*)*";
        //const String URL_REG_EXP = @"(https?|ftp|file)\://[A-Za-z0-9\.\-?_=&{}$\p{S}\p{C}\\%!\(\)]+(/[A-Za-z0-9\?\&\=;\+!'\(\)\*\-\._~${}%\p{S}\p{C}\\\(\)]*)*";
        const String URL_REG_EXP = @"(https?|ftp|file)\://[A-Za-z0-9\.\-?_=&{}$\u3041-\u3096\u30A0-\u30FF\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A\u2E80-\u2FD5\uFF5F-\uFF9F\u3000-\u303F\u31F0-\u31FF\u3220-\u3243\u3280-\u337F\uFF01-\uFF5E\\%!\(\)]+(/[A-Za-z0-9\?\&\=;\+!'\(\)\*\-\._~${}%\u3041-\u3096\u30A0-\u30FF\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A\u2E80-\u2FD5\uFF5F-\uFF9F\u3000-\u303F\u31F0-\u31FF\u3220-\u3243\u3280-\u337F\uFF01-\uFF5E\\\(\)]*)*";
        //const String TEXT_URL_REG_EXP = @"(https?|ftp|file)\://[A-Za-z0-9\.\-]+(/[A-Za-z0-9\?\&\=;\+!'\(\)\*\-\._~${}%]*)*";
        const String TEXT_URL_REG_EXP = @"(https?|ftp|file)\://[A-Za-z0-9\.\-?_=&{}$\u3041-\u3096\u30A0-\u30FF\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A\u2E80-\u2FD5\uFF5F-\uFF9F\u3000-\u303F\u31F0-\u31FF\u3220-\u3243\u3280-\u337F\uFF01-\uFF5E\\%!\(\)]+(/[A-Za-z0-9\?\&\=;\+!'\(\)\*\-\._~${}%\u3041-\u3096\u30A0-\u30FF\u3400-\u4DB5\u4E00-\u9FCB\uF900-\uFA6A\u2E80-\u2FD5\uFF5F-\uFF9F\u3000-\u303F\u31F0-\u31FF\u3220-\u3243\u3280-\u337F\uFF01-\uFF5E\\\(\)]*)*";




        static RegexOptions myRegexOptions = RegexOptions.IgnoreCase
                                      | RegexOptions.CultureInvariant
                                      | RegexOptions.IgnorePatternWhitespace
                                      | RegexOptions.Compiled
                                      | RegexOptions.Singleline;





        public static List<RegexResult> GetAllURLs(string InputFileString, FileType fileType)
        {

            String REGEX_PATTERN = GetURLPattern(fileType);
            Regex regURLPattern = new Regex(REGEX_PATTERN, myRegexOptions);

            // Get a collection of matches.
            MatchCollection urlMatchCollection = regURLPattern.Matches(InputFileString);
            List<RegexResult> result = new List<RegexResult>();
            for (int i = 0; i < urlMatchCollection.Count; i++)
                //if (!result.Contains(urlMatchCollection[i].Value))

                result.Add(new RegexResult { Index = urlMatchCollection[i].Index, Value = urlMatchCollection[i].Value });

            return result;
        }






        private static string GetURLPattern(FileType fileType)
        {
            if (fileType == FileType.HTML)
                return URL_REG_EXP;
            else
                return TEXT_URL_REG_EXP;
        }

        private static string GetHREFPattern()
        {
            return "href=\"(.*?(\n|\r|\r\n))+" + URL_REG_EXP + "\""; // ADD HREF,,,, END WITH ";
        }




        public static string FindAppyRuleAndThenReplace(string inputString,
                                                 FileType inputFileType,
                                                 List<String> IncludeUrls,
                                                 List<String> ExcludeUrls,
                                                 Hashtable UserParameters,
                                                 String MainParameters
                                                , System.Windows.Forms.ListBox listStatus
                                                , ref System.Windows.Forms.RichTextBox rtfUrlList
                                                , ref System.Windows.Forms.RichTextBox rtfUrlRulesApplied)
        {

            String RegexPattern = (inputFileType == FileType.HTML ? GetHREFPattern() : GetURLPattern(inputFileType));

            StringBuilder matchedUrls = new StringBuilder();
            StringBuilder updatedMatchedUrls = new StringBuilder();
            //Regex.Replace(inputString, RegexPattern, RuleAppyToMatch);
            bool isFirstUrl = true;
            String outputString = Regex.Replace(inputString, RegexPattern, delegate(Match m)
            {
                // logger.Info(m.Value);
                
                matchedUrls.AppendLine(m.Value);
                listStatus.Items.Add("URL Matched: " + m.Value);
                String matchedString = String.Empty;
                String OutputString = String.Empty;
                if (inputFileType == FileType.TEXT)
                {
                    matchedString = m.Value;
                    OutputString = ApplyRulesToURL(matchedString, inputFileType, IncludeUrls, ExcludeUrls, UserParameters, MainParameters, isFirstUrl);
                }
                else if (inputFileType == FileType.HTML)
                {
                    List<RegexResult> UrlsInsideHREF = URLUtilities.GetAllURLs(m.Value, inputFileType);
                    String CurrentUrlInsideHREF = UrlsInsideHREF[0].Value;
                    matchedString = CurrentUrlInsideHREF;
                    String OutputUrl = ApplyRulesToURL(matchedString, inputFileType, IncludeUrls, ExcludeUrls, UserParameters, MainParameters, isFirstUrl);
                    OutputString = m.Value.Replace(CurrentUrlInsideHREF, OutputUrl);
                }
                //logger.Info(OutputString);
                listStatus.Items.Add("URL Updated: " + OutputString);
                updatedMatchedUrls.AppendLine(OutputString);
                if (isFirstUrl == true)
                    isFirstUrl = false;
                return OutputString;
            }, myRegexOptions);

            rtfUrlList.Text = matchedUrls.ToString();
            rtfUrlRulesApplied.Text = updatedMatchedUrls.ToString();

            return outputString;


        }


        public static string ApplyRulesToURL(string inputUrlString,
                                                 FileType inputFileType,
                                                 List<String> IncludeUrls,
                                                 List<String> ExcludeUrls,
                                                 Hashtable UserParameters,
                                                 String MainParameters,
                                                 bool isFirstUrl)
        {



            List<String> NewUrlParameters = new List<string>();

            //logger.Trace(inputString);
            String outputURL = inputUrlString;

            bool moreRulesToApply = true;

            if (UserParameters.ContainsKey("cancel"))
            {
                // 1. Check if inputUrl has Cancel in the keyword
                //    Do nothing return the original Url
                if (moreRulesToApply && RuleValidator.CancelFoundInUrl(inputUrlString))
                {
                    moreRulesToApply = false;
                }
            }

            if (moreRulesToApply && RuleValidator.PartialMatchForUrl(inputUrlString, IncludeUrls))
            {
                if (inputFileType == FileType.TEXT)
                {
                    
                    if (moreRulesToApply && RuleValidator.ExactMatchForUrl(inputUrlString, ExcludeUrls) && isFirstUrl == true )
                    {
                        moreRulesToApply = false;
                    }
                }



                if (moreRulesToApply)
                {
                    foreach (var userParamKey in UserParameters.Keys)
                    {
                        var userParamValue = UserParameters[userParamKey];

                        if (moreRulesToApply && RuleValidator.MatchSubStringInUrl(inputUrlString, userParamKey.ToString()))
                        {
                            //outputURL = AppendParamterToUrl(outputURL, userParamValue.ToString());
                            NewUrlParameters.Add(CleanParamater(userParamValue.ToString()));

                            moreRulesToApply = false; // This Rule is applied and expect other rules can be applied
                        }
                    }
                }

                // 3. If Url has ? in the URL 
                //    a. Check if the parameter has starting character ? --> replace ? with &
                //    b. Append the newly created parameter in the inputString

                if (moreRulesToApply)
                {
                    //outputURL = AppendParamterToUrl(outputURL, MainParameters);
                    NewUrlParameters.Add(CleanParamater(MainParameters));
                    moreRulesToApply = false; // This Rule is applied and expect other rules can be applied
                }
            }

            outputURL = AppendParamterToUrl(inputUrlString, NewUrlParameters);



            //logger.Trace(outputURL);
            //logger.Trace(Environment.NewLine);
            return outputURL;
        }

        private static string CleanParamater(string parameter)
        {
            // Remove the ? and & charcter fromt the start of the paramater 

            String cleanParam = parameter;
            if (parameter.StartsWith("?") || parameter.StartsWith("&"))
            {
                cleanParam = parameter.Substring(1); // Remove the Fist "&"
            }
            return cleanParam.Trim();
        }

        private static string AppendParamterToUrl(string inputUrlString, List<string> NewUrlParameters)
        {
            String outpurUrl = String.Empty;
            if (NewUrlParameters.Count == 0)
            {
                outpurUrl = inputUrlString; // No Change Required
            }
            else
            {
                StringBuilder NewParamaterString = new StringBuilder();

                for (int i = 0; i < NewUrlParameters.Count; i++)
                {
                    if (i == 0)
                    {
                        NewParamaterString.Append(NewUrlParameters[i]);
                    }
                    else
                    {
                        NewParamaterString.Append("&" + NewUrlParameters[i]);
                    }
                }



                
                String UrlWithOutParamaters = String.Empty;
                String OtherParameters = String.Empty;

                if (RuleValidator.QuestionMarkFoundInUrl(inputUrlString))
                {
                    outpurUrl = inputUrlString + "&" + NewParamaterString.ToString();
                }

                else
                {
                    outpurUrl = inputUrlString + "?" + NewParamaterString.ToString();
                }

            }

            return outpurUrl;


        }




        public static string AppendParamterToUrl(string Url, string parameter)
        {

            String inputUrl = Url;
            string outputUrl = inputUrl;

            string newParameter = parameter;



            if (RuleValidator.QuestionMarkFoundInUrl(inputUrl))
            {
                if (parameter.StartsWith("?"))
                {
                    newParameter = parameter.Replace("?", "&");
                }
                else if (!parameter.StartsWith("&"))
                {
                    newParameter = "&" + parameter;
                }

            }
            else
            {
                if (parameter.StartsWith("&"))
                    newParameter = parameter.Replace('&', '?');
                else if (!parameter.StartsWith("?"))
                {
                    newParameter = "?" + parameter;
                }
            }



            //bool hasSpecialCharacters = HasSpecialCharInString(inputUrl);


            outputUrl = inputUrl + newParameter;
            return outputUrl;
        }

        public static bool HasSpecialCharInString(string word)
        {

            bool containUnicode = false;
            for (int x = 0; x < word.Length; x++)
            {
                UnicodeCategory uCat = char.GetUnicodeCategory(word[x]);

                if (uCat == UnicodeCategory.OtherSymbol ||
                    uCat == UnicodeCategory.OtherNumber ||
                    uCat == UnicodeCategory.OtherNotAssigned ||
                    uCat == UnicodeCategory.OtherLetter ||
                    uCat == UnicodeCategory.Control
                    )
                {
                    containUnicode = true;
                    break;
                }
            }
            return containUnicode;
        }







    }
}
